package com.sunday.gateway.core.exception;

import com.sunday.common.core.enums.ErrorCodeEnum;
import com.sunday.common.core.remoting.rest.response.RestResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

/**
 * ErrorWebExceptionHandler 是用于处理在 WebFlux 应用程序中发生的错误的接口。
 * 当应用程序发生异常时，将会调用 handleError 函数。
 *
 * @author sunday
 * @since 2024/1/31
 */
@Slf4j
@Component
/**
 * {@link org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration#errorWebExceptionHandler(ErrorAttributes, WebProperties, ObjectProvider, ServerCodecConfigurer, ApplicationContext)}
 * DefaultErrorWebExceptionHandler的默认顺序是-1。
 * 因此，如果你想让你自定义的CustomErrorWebExceptionHandler在这些默认的异常处理器之前执行，你需要给它一个更小的顺序值，如-2。
 */
@Order(-2)
public class ResponseErrorWebExceptionHandler implements ErrorWebExceptionHandler {

    /**
     * 处理给定的异常。通过返回值的完成信号
     * 指示错误处理完成，而错误信号指示
     * 仍然未处理异常。
     * {@link org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping#lookupRoute(ServerWebExchange)}
     * {@link org.springframework.web.reactive.resource.ResourceWebHandler#handle(ServerWebExchange)}
     *
     * @param exchange
     * @param ex
     * @return {@link Mono< Void>}
     * @see org.springframework.web.server.handler.ExceptionHandlingWebHandler
     * @see org.springframework.web.reactive.handler.WebFluxResponseStatusExceptionHandler
     */
    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {

        log.error(ex.toString(), ex);

        ServerHttpResponse response = exchange.getResponse();

        RestResponse restResponse = RestResponse.error(ErrorCodeEnum.A0_400);

        // 设置响应的报文头
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        // 设置响应的状态码
        response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);

        // 将错误信息写入响应中
        DataBuffer buffer = response.bufferFactory().wrap(restResponse.toString().getBytes(StandardCharsets.UTF_8));

        return response.writeWith(Mono.just(buffer));
    }


}
